package com.fleapx.moreclumnexecldata;

import com.fleapx.moreclumnexecldata.bean.OperationData;
import com.fleapx.moreclumnexecldata.bean.Worksheet;
import com.google.common.collect.Lists;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.apache.log4j.Logger;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 类功能描述：generator big data Excel
 *
 * @author itdebug create at 19-4-13 下午10:23
 * @version 1.0.0
 */
public class ExcelGenerator {
    private static Logger log = Logger.getLogger(ExcelGenerator.class);
    private final static int ONE_SHEET_LIMIT_ROW = 65535;

    public static void main(String[] args) throws FileNotFoundException {
        List<OperationData> dataList = first_one_million_pieces_of_data_are_generated();
        writeExcelOneSheetByList("operation_data_",new File("D:\\ceshi\\test\\"),
                "itdebug25milliondata.xml",OperationData.class,averageAssignList(dataList,20000));
    }

    //1.首先生成100万条数据：
    public static List<OperationData> first_one_million_pieces_of_data_are_generated() throws FileNotFoundException {
        List<OperationData> dataList = Lists.newArrayList();
        for (int i = 0; i < 1000000; i++) {
            int val = (int) (Math.random() * 10 + 1);
            OperationData operationData = new OperationData();
            operationData.setAvgMakeLoanAm("4343" + val).setBackOrderAmount("4343" + val).setBadCardNumber("4343" + val)
                    .setCardPeriod("4343" + val).setConPg("4343" + val)
                    .setConPg90("4343" + val).setEndInventAm("4343" + val).setEndInventAm("4343" + val)
                    .setFactFee("4343" + val).setFee("4343" + val).setFirstContYear("4343" + val).setLossNum("4343" + val)
                    .setGroupNumber("4343" + val).setCardNumber("4343" + val)
                    .setMakeLoanInt("4343" + val).setMakeLoanNum("4343" + val)
                    .setNetPg("4343" + val).setOrderAmount("4343" + val).setOverdueInt("4343" + val)
                    .setMakeLoanAm("4343" + val).setOverdueNum("4343" + val)
                    .setOverdueNum("4343" + val).setSaleAmount("4343" + val).setReceiveOrderAmount("4343" + val)
                    .setSaleAmount90("4343" + val).setSaleAmount180("4343" + val)
                    .setSaleRecord("4343" + val).setSupplierName("4343" + val)
                    .setOrderNumber("4343" + val).setReceiveRecord("4343" + val);
            dataList.add(operationData);
        }
        return dataList;
    }
    //2.我们假定每次插入Excel为2万行，我们先拆分这100万行数据
    /**
     * 将一个list均分成n个list,主要通过偏移量来实现的
     * @param source
     * @return
     */
    public static <T> List<List<T>> averageAssignList(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n;  //(先计算出余数)
        int number = source.size() / n;  //然后是商
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }
    /**
     * 3.最后，我们来看下我们生成Excel方法如下
     * 写入单个Sheet的Excel operation_data_
     *
     * @param templatePrefix 模板前缀，默认两个模板后缀分别为head及body
     * @param outFile        生成Excel文件
     * @param sheetName      单个sheet名称
     * @param dataList       填充数据列表
     * @param <T>            填充对象泛型
     * @throws FileNotFoundException
     * @throws ClassNotFoundException
     */
    public static <T> void writeExcelOneSheetByList(String templatePrefix, File outFile, String sheetName, Class clazz, List<List<T>> dataList) {
        long startTimne = System.currentTimeMillis();
        StringTemplateGroup stGroup = new StringTemplateGroup(String.valueOf(startTimne));
        try (PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(outFile)))) {
            //写入excel文件头部信息
            StringTemplate head = stGroup.getInstanceOf("template" + File.separator + templatePrefix + "head");
            writer.print(head.toString());
            writer.flush();
            //excel单表最大行数是65535
            Field[] fields = clazz.getDeclaredFields();
            dataList.forEach(x -> {
                long startTimne1 = System.currentTimeMillis();
                //写入excel文件数据信息
                StringTemplate body = stGroup.getInstanceOf("template" + File.separator + templatePrefix + "body");
                Worksheet worksheet = new Worksheet();
                worksheet.setSheet(sheetName);
                worksheet.setColumnNum(fields.length);
                worksheet.setRowNum(ONE_SHEET_LIMIT_ROW);
                worksheet.setRows(x);
                body.setAttribute("worksheet", worksheet);
                writer.print(body.toString());
                writer.flush();
                long endTime1 = System.currentTimeMillis();
                System.out.println("用时=" + ((endTime1 - startTimne1) / 1000) + "秒");
            });
            //写入excel文件foot部信息
            StringTemplate foot = stGroup.getInstanceOf("template" + File.separator + templatePrefix + "foot");
            writer.print(foot.toString());
            writer.flush();
        } catch (Exception e) {
            log.error("写入Excel异常", e);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用时=" + ((endTime - startTimne) / 1000) + "秒");
    }
}